/*
 meshgeneration.cpp
 Matthew Jee
 mcjee@ucsc.edu
*/

#include "meshgeneration.h"
#include "debug.h"
#include <map>

namespace mj {

static mj::Vector4 _colors[] = {
    mj::Vector4(1.0, 0.0, 0.0, 1.0),
    mj::Vector4(0.0, 1.0, 0.0, 1.0),
    mj::Vector4(1.0, 0.0, 1.0, 1.0),
    mj::Vector4(0.0, 1.0, 1.0, 1.0)
};

// ignores color now
Mesh *generatePathMesh(std::vector<Path> &paths, Vector4 userColor) {
    std::vector<GLfloat> vertices;
    std::vector<GLuint> indices;
    std::map<int, Vector4> colors;

    for (size_t i = 0; i < paths.size(); ++i) {
        Path &path = paths[i];
        
        //float t = 1.0*i/paths.size();
        Vector4 color = userColor;
        if (userColor.r < 0.0) {
            if (colors.find(path[0].pathID) == colors.end()) {
                if (path[0].pathID > 3) {
                    colors[path[0].pathID] = Vector4(
                        1.0*rand()/RAND_MAX,
                        1.0*rand()/RAND_MAX,
                        1.0*rand()/RAND_MAX,
                        1.0
                    );
                } else {
                    colors[path[0].pathID] = _colors[path[0].pathID];
                }
            }
            color = colors[path[0].pathID];
        }

        for (size_t j = 0; j < path.size(); ++j) {
            Point &point = path[j];
            point.pathID = i;
            vertices.push_back(point.position.x);
            vertices.push_back(point.position.y);
            vertices.push_back(point.position.z);

            vertices.push_back(color.r);
            vertices.push_back(color.g);
            vertices.push_back(color.b);
            vertices.push_back(color.a);

            if (j+1 < path.size()) {
                Point &nextPoint = path[j+1];
                vertices.push_back(nextPoint.position.x);
                vertices.push_back(nextPoint.position.y);
                vertices.push_back(nextPoint.position.z);

                vertices.push_back(color.r);
                vertices.push_back(color.g);
                vertices.push_back(color.b);
                vertices.push_back(color.a);

                indices.push_back(vertices.size()/7-2);
                indices.push_back(vertices.size()/7-1);
            }
        }
    }
    return new Mesh(&vertices[0], &indices[0], vertices.size()/7, indices.size(), 7);
}

Mesh * generateLargeMesh(std::vector<Cluster> &clusters, int resolution, GLfloat size, GLfloat alpha) {

    std::vector<GLfloat> vertices;
    std::vector<GLuint> indices;
    std::map<int, Vector4> colors;

    for (size_t i = 0; i < clusters.size(); i++) {

        Cluster *cluster = &clusters[i];
        size_t pointCount = cluster->points.size();

        if (colors.find(cluster->tag) == colors.end()) {
            if (cluster->tag > 3) {
                colors[cluster->tag] = Vector4(
                    1.0*rand()/RAND_MAX,
                    1.0*rand()/RAND_MAX,
                    1.0*rand()/RAND_MAX,
                    1.0
                );
            } else {
                colors[cluster->tag] = _colors[cluster->tag];
            }
        }
        Vector4 color = colors[cluster->tag];

        for (size_t j = 0; j < pointCount; ++j) {
            GLfloat x = cluster->points[j].position.x;
            GLfloat y = cluster->points[j].position.y;

            GLuint centerIndex = vertices.size()/7;
            // add one vertex at the center
            vertices.push_back(x);
            vertices.push_back(y);
            vertices.push_back(0);

            vertices.push_back(color.r);
            vertices.push_back(color.g);
            vertices.push_back(color.b);
            vertices.push_back(alpha);
            // add one triangle for each 'res'
            for (int k = 0; k < resolution; k++) {
                GLfloat theta1 = k*1.0/resolution*M_PI*2;
                
                vertices.push_back(x+cosf(theta1)*size);
                vertices.push_back(y+sinf(theta1)*size);
                vertices.push_back(0);

                vertices.push_back(color.r);
                vertices.push_back(color.g);
                vertices.push_back(color.b);
                vertices.push_back(0.0);

                indices.push_back(centerIndex);
                indices.push_back(centerIndex+k+1);
                indices.push_back(centerIndex+((k+1) % resolution)+1);
            }
        }
    }

    return new Mesh(&vertices[0], &indices[0], vertices.size()/7, indices.size(), 7);
}

}
